using System;
using System.Globalization;
using System.Collections.Generic;
using System.Text;
using System.Net;
using System.IO;
using Winista.Text.HtmlParser;
using Winista.Text.HtmlParser.Tags;
using Winista.Text.HtmlParser.Lex;
using Winista.Text.HtmlParser.Filters;
using Winista.Text.HtmlParser.Util;


namespace Timesheet
{
    class HttpHelper
    {
        private Encoding encoding = Encoding.GetEncoding("utf-8");
        private CookieContainer cookieContainer = new CookieContainer();
        private string openairUrl = "https://www.openair.com/";
        

        //navigate to Timesheets page
        public string ListTimesheets(string html)
        {
            //list all open timesheets
            string timesheet_layout = "_timesheet_layout=open";
            string flist_timesheet_filter_sheetdate = "_flist_timesheet_filter_sheetdate=__ALL";
            string _flist_timesheet_filter_sheetname = "_flist_timesheet_filter_sheetname=__ALL";

            string linkName = "Timesheets";
            try
            {

                string listLink = getParsingLink(html, linkName);
                string listOpenLink = listLink + ";" + timesheet_layout + ";" + flist_timesheet_filter_sheetdate + ";" + _flist_timesheet_filter_sheetname;
                if (!String.IsNullOrEmpty(listLink))
                {
                    string listOpenUrl = this.openairUrl + listOpenLink;
                    string method = "GET";
                    return connectOpenair(listOpenUrl, method, "");
                }
                return null;
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.StackTrace);
                throw ex;
            }
        }

        //verify if have created the timesheet for this week
        public string GetTimesheetForDate(DateTime date, string listHtml)
        {
            //assume date is friday
            DateTime lastSaturday = date.AddDays(-6);
            // FixMe : we will get problem when time go to Year 2100.
            int dateYear = (date.Year - 2000);
            int lastSaturdayYear = (lastSaturday.Year - 2000);
            string timeSheetName = "Timesheet for " + lastSaturday.ToString("d", DateTimeFormatInfo.InvariantInfo).Substring(0, 6) + lastSaturdayYear + " to " + date.ToString("d", DateTimeFormatInfo.InvariantInfo).Substring(0, 6) + dateYear;
            string timeSheetNameInstead = "Timesheet for " + lastSaturday.ToString("dd-MM-yyyy") + " to " + date.ToString("dd-MM-yyyy");
            string timeSheetNameInstead2 = "Timesheet for " + lastSaturday.ToString("MM/dd/yyyy") + " to " + date.ToString("MM/dd/yyyy");
            try
            {
                string linkForThisWeek = "";
                linkForThisWeek = getParsingLink(listHtml, timeSheetName);
                if (String.IsNullOrEmpty(linkForThisWeek))
                {
                    linkForThisWeek = getParsingLink(listHtml, timeSheetNameInstead);
                }
                if (String.IsNullOrEmpty(linkForThisWeek))
                {
                    linkForThisWeek = getParsingLink(listHtml, timeSheetNameInstead2);
                }
                return linkForThisWeek;
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.StackTrace);
                throw ex;
            }

        }

        //get the link to create timesheet
        public string GetCreateTimesheetLink(string html)
        {
            try
            {
                string createTimesheetLink = "";
                string linkName = "Timesheet";
                createTimesheetLink = getParsingLink(html, linkName);
                return createTimesheetLink;
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.StackTrace);
                throw ex;
            }
   
        }

        //create timesheet for this week
        public string CreateTimesheet(string createTimesheetLink, string range)
        {
            string createTimesheetUrl = this.openairUrl + createTimesheetLink;
            string timesheetAttribute = createTimesheetLink.Replace("timesheet.pl?", "").Replace(";", "&");
            string createData = timesheetAttribute + "&range=" + range + "&_form_has_changed=0&_FORM_SUBMIT=1&_RAN=80970426&_STRIP=save&_DATA_FIELDS=customer_project%2Cpayroll_type%2Cnotes%2Crange&_NUMBER_FIELDS=&_POPUP_FIELDS=customer_project%2C%3A%2Cpayroll_type%2C__BLANK%2Crange%2C__BLANK&_DATE_FIELDS=&_TIME_FIELDS=&_GT_ZERO_FIELDS=&_GE_ZERO_FIELDS=&_EMAIL_FIELDS=&_PASSWORD_FIELDS=&_FILE_FIELDS=&_REQUIRED_FIELDS=&_UNIQUE_FIELDS=&_HIDDEN_FIELDS=__fm_name%2C_cleared_timesheet_attachment_temp_files%2C__save_and_create_form_name_fallback&_MAXPRECISION=&_RULES_REQ_FIELDS=&__fm_name=new_timesheet_form&_cleared_timesheet_attachment_temp_files=1&__save_and_create_form_name_fallback=new_timesheet_form&customer_project=%3A&payroll_type=BLANK&notes=&save=Create+the+timesheet";
            string method = "POST";
            try
            {
                return connectOpenair(createTimesheetUrl, method, createData);
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.StackTrace);
                throw ex;
            }

        }

        //submit the work data for this week
        public void SubmitTimesheet(string timesheetForWeek, string workData, string date)
        {
            string submitTimesheetUrl = this.openairUrl + timesheetForWeek;

            string timesheetAttribute = timesheetForWeek.Replace("timesheet.pl?", "").Replace(";", "&");
            string submitData = "_form_has_changed=1" + "&" + timesheetAttribute + "&_popups=cp_id&_popups=pt_id&_popups=payroll_type_id&_date=" + DateTime.Now.ToString("yyyy-MM-dd", DateTimeFormatInfo.InvariantInfo) + "&_pop_cols=3&_grid_custom_fields=custom_42&_left_grid_custom_fields=&_dialog_fields=notes&_dialog_fields=sri&_add_rows=BLANK" + workData + "&_save_grid=Save";
            string method = "POST";
            try
            {
                string returnHtml = connectOpenair(submitTimesheetUrl, method, submitData);
                if (!returnHtml.Contains("The timesheet was saved"))
                {
                    throw new Exception("The timesheet wasn't saved");
                }
            }

            catch (Exception ex)
            {
                Console.WriteLine(ex.StackTrace);
                throw ex;
            }       
            
        }


        public string LogInByOpenair(string account, string openairPassword)
        {
            string postData = "_form_has_changed=0&_FORM_SUBMIT=1&_RAN=84922254&_STRIP=login&_DATA_FIELDS=account_nickname%2Cpassword%2Cstoreid%2Cuser_nickname%2C_namespace%2Cjump_to%2C_sso%2C_key%2C_clear_branding%2Cadd_default_terms%2Clast_uid&_NUMBER_FIELDS=&_POPUP_FIELDS=&_DATE_FIELDS=&_TIME_FIELDS=&_GT_ZERO_FIELDS=&_GE_ZERO_FIELDS=&_EMAIL_FIELDS=&_PASSWORD_FIELDS=password&_FILE_FIELDS=&_REQUIRED_FIELDS=&_UNIQUE_FIELDS=&_HIDDEN_FIELDS=_namespace%2Cjump_to%2C_sso%2C_key%2C_clear_branding%2Cadd_default_terms%2Clast_uid&_MAXPRECISION=&_RULES_REQ_FIELDS=&_namespace=&jump_to=&_sso=&_key=&_clear_branding=&add_default_terms=&last_uid=&account_nickname=redprairie&user_nickname=" + account + "&password=" + openairPassword + "&login=Log+in";
            string loginUrl = "https://www.openair.com/index.pl";
            string method = "POST";
            try
            {
                return connectOpenair(loginUrl, method, postData);
            }
            catch(Exception ex)
            {
                Console.WriteLine(ex.StackTrace);
                throw ex;
            }
        }


        /// <summary>
        /// Log in to Hydra
        /// </summary>
        /// <param name="account"></param>
        /// <param name="openairPassword"></param>
        /// <returns></returns>
        public string LogInToHydra(string account, string password)
        {
            string postData = "username=" + account + "&password=" + password + "&lt=_cA1A7EC65-AD0E-875B-DF81-7A40B31D8473_kD5DA7BA0-C887-CF4E-C1BE-A96FE791E1FB&_eventId=submit&submit=LOGIN";
            string loginUrl = "https://hydra.bleum.com:8080/cas/login?service=https%3A%2F%2Fhydra.bleum.com%2Fproject%2Fj_acegi_cas_security_check%3Bjsessionid%3D2A06B0632EDA1780E923A524D4BDD39E";
            string method = "POST";
            try
            {
                return connectHydra(loginUrl, method, postData);
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.StackTrace);
                throw ex;
            }
        }

        public string LogInTo51CTO(string account, string password)
        {
            //string postData = "username=" + account + "&password=" + password + "&lt=_cA1A7EC65-AD0E-875B-DF81-7A40B31D8473_kD5DA7BA0-C887-CF4E-C1BE-A96FE791E1FB&_eventId=submit&submit=LOGIN";
            string postData = "email=" + account+ "&passwd=" + password + "&reback=http%253A%252F%252Fwww.51cto.com%252F&button.x=62&button.y=19";
            string loginUrl = "http://home.51cto.com/index.php?s=/Index/doLogin";
            string method = "POST";
            try
            {
                return connectHydra(loginUrl, method, postData);
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.StackTrace);
                throw ex;
            }
        }

        private string getParsingLink(string html, string linkName)
        {
            Lexer lexer = new Lexer(html);
            Parser parser = new Parser(lexer);
            NodeFilter nodeFilter = new LinkRegexFilter("timesheet\\w*");

            NodeList htmlNodes = parser.Parse(nodeFilter);
            string parsingLink = "";
            for (int i = 0; i < htmlNodes.Count; i++)
            {
                string text = (htmlNodes.ElementAt(i).Children).ToHtml();
                if (text.Equals(linkName))
                {
                    string linkText = htmlNodes.ElementAt(i).GetText();
                    int begin = linkText.IndexOf("href=\"") + "href=\"".Length;
                    parsingLink = linkText.Substring(begin, linkText.Length - begin - 1);
                    break;
                }
            }
            if (!String.IsNullOrEmpty(parsingLink))
            {
                return parsingLink;
            }
            return null;
        }

        private string connectOpenair(string url, string method, string data)
        {
            byte[] request = Encoding.Default.GetBytes(data);
            HttpWebRequest req = (HttpWebRequest)HttpWebRequest.Create(url);


            req.Method = method;
            req.KeepAlive = true;
            //save the cookie
            req.CookieContainer = this.cookieContainer;

            if (!String.IsNullOrEmpty(data))
            {
                req.ContentLength = request.Length;
                Stream reqStream = req.GetRequestStream();
                reqStream.Write(request, 0, request.Length);
                reqStream.Close();
            }
            
            HttpWebResponse res;
            res = (HttpWebResponse)req.GetResponse();
            Stream resStream = res.GetResponseStream();
            StreamReader reader = new StreamReader(resStream, this.encoding);
            string html = reader.ReadToEnd();
            reader.Close();
            resStream.Close();

            return html;
        }

        /// <summary>
        /// Connect to Hydra
        /// </summary>
        /// <param name="url"></param>
        /// <param name="method"></param>
        /// <param name="data"></param>
        /// <returns></returns>
        private string connectHydra(string url, string method, string data)
        {
            byte[] request = Encoding.Default.GetBytes(data);
            HttpWebRequest req = (HttpWebRequest)HttpWebRequest.Create(url);


            req.Method = method;
            req.KeepAlive = true;
            //save the cookie
            req.CookieContainer = this.cookieContainer;

            if (!String.IsNullOrEmpty(data))
            {
                req.ContentLength = request.Length;
                Stream reqStream = req.GetRequestStream();
                reqStream.Write(request, 0, request.Length);
                reqStream.Close();
            }

            HttpWebResponse res;
            res = (HttpWebResponse)req.GetResponse();
            Stream resStream = res.GetResponseStream();
            StreamReader reader = new StreamReader(resStream, this.encoding);
            string html = reader.ReadToEnd();
            reader.Close();
            resStream.Close();

            return html;
        }

    }    
}
